Completed
Push — master ( 369c90...324e29 )
by Michael
04:57
created

$.fn.extend.result   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
/*
2
 * Autocomplete - jQuery plugin 1.0.2
3
 *
4
 * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
5
 *
6
 * Dual licensed under the MIT and GPL licenses:
7
 *   http://www.opensource.org/licenses/mit-license.php
8
 *   http://www.gnu.org/licenses/gpl.html
9
 *
10
 * Revision: $Id: jquery.autocomplete.js 2 2010-01-23 20:04:25Z hthouzard $
11
 *
12
 */
13
14
;(function ($) {
15
16
    $.fn.extend({
17
        autocomplete: function (urlOrData, options) {
18
            var isUrl = typeof urlOrData == "string";
19
            options = $.extend({}, $.Autocompleter.defaults, {
20
                url: isUrl ? urlOrData : null,
21
                data: isUrl ? null : urlOrData,
22
                delay: isUrl ? $.Autocompleter.defaults.delay : 10,
23
                max: options && !options.scroll ? 10 : 150
24
            }, options);
25
26
            // if highlight is set to false, replace it with a do-nothing function
27
            options.highlight = options.highlight || function (value) {
28
                    return value;
29
                };
30
31
            // if the formatMatch option is not specified, then use formatItem for backwards compatibility
32
            options.formatMatch = options.formatMatch || options.formatItem;
33
34
            return this.each(function () {
35
                new $.Autocompleter(this, options);
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new $.Autocompleter(this, options) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
36
            });
37
        },
38
        result: function (handler) {
39
            return this.bind("result", handler);
40
        },
41
        search: function (handler) {
42
            return this.trigger("search", [handler]);
43
        },
44
        flushCache: function () {
45
            return this.trigger("flushCache");
46
        },
47
        setOptions: function (options) {
48
            return this.trigger("setOptions", [options]);
49
        },
50
        unautocomplete: function () {
51
            return this.trigger("unautocomplete");
52
        }
53
    });
54
55
    $.Autocompleter = function (input, options) {
56
57
        var KEY = {
58
            UP: 38,
59
            DOWN: 40,
60
            DEL: 46,
61
            TAB: 9,
62
            RETURN: 13,
63
            ESC: 27,
64
            COMMA: 188,
65
            PAGEUP: 33,
66
            PAGEDOWN: 34,
67
            BACKSPACE: 8
68
        };
69
70
        // Create $ object for input element
71
        var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
72
73
        var timeout;
74
        var previousValue = "";
75
        var cache = $.Autocompleter.Cache(options);
76
        var hasFocus = 0;
77
        var lastKeyPressCode;
78
        var config = {
79
            mouseDownOnSelect: false
80
        };
81
        var select = $.Autocompleter.Select(options, input, selectCurrent, config);
82
83
        var blockSubmit;
84
85
        // prevent form submit in opera when selecting with return key
86
        $.browser.opera && $(input.form).bind("submit.autocomplete", function () {
87
            if (blockSubmit) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if blockSubmit is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
88
                blockSubmit = false;
89
                return false;
90
            }
91
        });
92
93
        // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
94
        $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function (event) {
95
            // track last key pressed
96
            lastKeyPressCode = event.keyCode;
97
            switch (event.keyCode) {
98
99
                case KEY.UP:
100
                    event.preventDefault();
101
                    if (select.visible()) {
102
                        select.prev();
103
                    } else {
104
                        onChange(0, true);
105
                    }
106
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
107
108
                case KEY.DOWN:
109
                    event.preventDefault();
110
                    if (select.visible()) {
111
                        select.next();
112
                    } else {
113
                        onChange(0, true);
114
                    }
115
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
116
117
                case KEY.PAGEUP:
118
                    event.preventDefault();
119
                    if (select.visible()) {
120
                        select.pageUp();
121
                    } else {
122
                        onChange(0, true);
123
                    }
124
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
125
126
                case KEY.PAGEDOWN:
127
                    event.preventDefault();
128
                    if (select.visible()) {
129
                        select.pageDown();
130
                    } else {
131
                        onChange(0, true);
132
                    }
133
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
134
135
                // matches also semicolon
136
                case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
137
                case KEY.TAB:
138
                case KEY.RETURN:
139
                    if (selectCurrent()) {
140
                        // stop default to prevent a form submit, Opera needs special handling
141
                        event.preventDefault();
142
                        blockSubmit = true;
143
                        return false;
144
                    }
145
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
146
147
                case KEY.ESC:
148
                    select.hide();
149
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
150
151
                default:
152
                    clearTimeout(timeout);
153
                    timeout = setTimeout(onChange, options.delay);
154
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
155
            }
156
        }).focus(function () {
157
            // track whether the field has focus, we shouldn't process any
158
            // results if the field no longer has focus
159
            hasFocus++;
160
        }).blur(function () {
161
            hasFocus = 0;
162
            if (!config.mouseDownOnSelect) {
163
                hideResults();
164
            }
165
        }).click(function () {
166
            // show select when clicking in a focused field
167
            if (hasFocus++ > 1 && !select.visible()) {
168
                onChange(0, true);
169
            }
170
        }).bind("search", function () {
171
            // TODO why not just specifying both arguments?
172
            var fn = (arguments.length > 1) ? arguments[1] : null;
173
174
            function findValueCallback(q, data) {
175
                var result;
176
                if (data && data.length) {
177
                    for (var i = 0; i < data.length; i++) {
178
                        if (data[i].result.toLowerCase() == q.toLowerCase()) {
179
                            result = data[i];
180
                            break;
181
                        }
182
                    }
183
                }
184
                if (typeof fn == "function") fn(result);
0 ignored issues
show
Bug introduced by
The variable result seems to not be initialized for all possible execution paths. Are you sure fn handles undefined variables?
Loading history...
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
185
                else $input.trigger("result", result && [result.data, result.value]);
186
            }
187
188
            $.each(trimWords($input.val()), function (i, value) {
189
                request(value, findValueCallback, findValueCallback);
190
            });
191
        }).bind("flushCache", function () {
192
            cache.flush();
193
        }).bind("setOptions", function () {
194
            $.extend(options, arguments[1]);
195
            // if we've updated the data, repopulate
196
            if ("data" in arguments[1])
197
                cache.populate();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
198
        }).bind("unautocomplete", function () {
199
            select.unbind();
200
            $input.unbind();
201
            $(input.form).unbind(".autocomplete");
202
        });
203
204
205
        function selectCurrent() {
206
            var selected = select.selected();
207
            if (!selected)
208
                return false;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
209
210
            var v = selected.result;
211
            previousValue = v;
212
213
            if (options.multiple) {
214
                var words = trimWords($input.val());
215
                if (words.length > 1) {
216
                    v = words.slice(0, words.length - 1).join(options.multipleSeparator) + options.multipleSeparator + v;
217
                }
218
                v += options.multipleSeparator;
219
            }
220
221
            $input.val(v);
222
            hideResultsNow();
223
            $input.trigger("result", [selected.data, selected.value]);
224
            return true;
225
        }
226
227
        function onChange(crap, skipPrevCheck) {
228
            if (lastKeyPressCode == KEY.DEL) {
229
                select.hide();
230
                return;
231
            }
232
233
            var currentValue = $input.val();
234
235
            if (!skipPrevCheck && currentValue == previousValue)
236
                return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
237
238
            previousValue = currentValue;
239
240
            currentValue = lastWord(currentValue);
241
            if (currentValue.length >= options.minChars) {
242
                $input.addClass(options.loadingClass);
243
                if (!options.matchCase)
244
                    currentValue = currentValue.toLowerCase();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
245
                request(currentValue, receiveData, hideResultsNow);
246
            } else {
247
                stopLoading();
248
                select.hide();
249
            }
250
        };
251
252
        function trimWords(value) {
253
            if (!value) {
254
                return [""];
255
            }
256
            var words = value.split(options.multipleSeparator);
257
            var result = [];
258
            $.each(words, function (i, value) {
259
                if ($.trim(value))
260
                    result[i] = $.trim(value);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
261
            });
262
            return result;
263
        }
264
265
        function lastWord(value) {
266
            if (!options.multiple)
267
                return value;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
268
            var words = trimWords(value);
269
            return words[words.length - 1];
270
        }
271
272
        // fills in the input box w/the first match (assumed to be the best match)
273
        // q: the term entered
274
        // sValue: the first matching result
275
        function autoFill(q, sValue) {
276
            // autofill in the complete box w/the first match as long as the user hasn't entered in more data
277
            // if the last user key pressed was backspace, don't autofill
278
            if (options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE) {
279
                // fill in the value (keep the case the user has typed)
280
                $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
281
                // select the portion of the value not typed by the user (so the next character will erase)
282
                $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
283
            }
284
        };
285
286
        function hideResults() {
287
            clearTimeout(timeout);
288
            timeout = setTimeout(hideResultsNow, 200);
289
        };
290
291
        function hideResultsNow() {
292
            var wasVisible = select.visible();
293
            select.hide();
294
            clearTimeout(timeout);
295
            stopLoading();
296
            if (options.mustMatch) {
297
                // call search and run callback
298
                $input.search(
299
                    function (result) {
300
                        // if no value found, clear the input box
301
                        if (!result) {
302
                            if (options.multiple) {
303
                                var words = trimWords($input.val()).slice(0, -1);
304
                                $input.val(words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : ""));
305
                            }
306
                            else
307
                                $input.val("");
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
308
                        }
309
                    }
310
                );
311
            }
312
            if (wasVisible)
313
            // position cursor at end of input field
314
                $.Autocompleter.Selection(input, input.value.length, input.value.length);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
315
        };
316
317
        function receiveData(q, data) {
318
            if (data && data.length && hasFocus) {
319
                stopLoading();
320
                select.display(data, q);
321
                autoFill(q, data[0].value);
322
                select.show();
323
            } else {
324
                hideResultsNow();
325
            }
326
        };
327
328
        function request(term, success, failure) {
329
            if (!options.matchCase)
330
                term = term.toLowerCase();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
331
            var data = cache.load(term);
332
            // recieve the cached data
333
            if (data && data.length) {
334
                success(term, data);
335
                // if an AJAX url has been supplied, try loading the data now
336
            } else if ((typeof options.url == "string") && (options.url.length > 0)) {
337
338
                var extraParams = {
339
                    timestamp: +new Date()
340
                };
341
                $.each(options.extraParams, function (key, param) {
342
                    extraParams[key] = typeof param == "function" ? param() : param;
343
                });
344
345
                $.ajax({
346
                    // try to leverage ajaxQueue plugin to abort previous requests
347
                    mode: "abort",
348
                    // limit abortion to this input
349
                    port: "autocomplete" + input.name,
350
                    dataType: options.dataType,
351
                    url: options.url,
352
                    data: $.extend({
353
                        q: lastWord(term),
354
                        limit: options.max
355
                    }, extraParams),
356
                    success: function (data) {
357
                        var parsed = options.parse && options.parse(data) || parse(data);
358
                        cache.add(term, parsed);
359
                        success(term, parsed);
360
                    }
361
                });
362
            } else {
363
                // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
364
                select.emptyList();
365
                failure(term);
366
            }
367
        };
368
369
        function parse(data) {
370
            var parsed = [];
371
            var rows = data.split("\n");
372
            for (var i = 0; i < rows.length; i++) {
373
                var row = $.trim(rows[i]);
374
                if (row) {
375
                    row = row.split("|");
376
                    parsed[parsed.length] = {
377
                        data: row,
378
                        value: row[0],
379
                        result: options.formatResult && options.formatResult(row, row[0]) || row[0]
380
                    };
381
                }
382
            }
383
            return parsed;
384
        };
385
386
        function stopLoading() {
387
            $input.removeClass(options.loadingClass);
388
        };
389
390
    };
391
392
    $.Autocompleter.defaults = {
393
        inputClass: "ac_input",
394
        resultsClass: "ac_results",
395
        loadingClass: "ac_loading",
396
        minChars: 1,
397
        delay: 400,
398
        matchCase: false,
399
        matchSubset: true,
400
        matchContains: false,
401
        cacheLength: 10,
402
        max: 100,
403
        mustMatch: false,
404
        extraParams: {},
405
        selectFirst: true,
406
        formatItem: function (row) {
407
            return row[0];
408
        },
409
        formatMatch: null,
410
        autoFill: false,
411
        width: 0,
412
        multiple: false,
413
        multipleSeparator: ", ",
414
        highlight: function (value, term) {
415
            return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
416
        },
417
        scroll: true,
418
        scrollHeight: 180
419
    };
420
421
    $.Autocompleter.Cache = function (options) {
422
423
        var data = {};
424
        var length = 0;
425
426
        function matchSubset(s, sub) {
427
            if (!options.matchCase)
428
                s = s.toLowerCase();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
429
            var i = s.indexOf(sub);
430
            if (i == -1) return false;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
431
            return i == 0 || options.matchContains;
432
        };
433
434
        function add(q, value) {
435
            if (length > options.cacheLength) {
436
                flush();
437
            }
438
            if (!data[q]) {
439
                length++;
440
            }
441
            data[q] = value;
442
        }
443
444
        function populate() {
445
            if (!options.data) return false;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
446
            // track the matches
447
            var stMatchSets = {},
448
                nullData = 0;
449
450
            // no url was specified, we need to adjust the cache length to make sure it fits the local data store
451
            if (!options.url) options.cacheLength = 1;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
452
453
            // track all options for minChars = 0
454
            stMatchSets[""] = [];
455
456
            // loop through the array and create a lookup structure
457
            for (var i = 0, ol = options.data.length; i < ol; i++) {
458
                var rawValue = options.data[i];
459
                // if rawValue is a string, make an array otherwise just reference the array
460
                rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
461
462
                var value = options.formatMatch(rawValue, i + 1, options.data.length);
463
                if (value === false)
464
                    continue;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
465
466
                var firstChar = value.charAt(0).toLowerCase();
467
                // if no lookup array for this character exists, look it up now
468
                if (!stMatchSets[firstChar])
469
                    stMatchSets[firstChar] = [];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
470
471
                // if the match is a string
472
                var row = {
473
                    value: value,
474
                    data: rawValue,
475
                    result: options.formatResult && options.formatResult(rawValue) || value
476
                };
477
478
                // push the current match into the set list
479
                stMatchSets[firstChar].push(row);
480
481
                // keep track of minChars zero items
482
                if (nullData++ < options.max) {
483
                    stMatchSets[""].push(row);
484
                }
485
            }
486
            ;
487
488
            // add the data items to the cache
489
            $.each(stMatchSets, function (i, value) {
490
                // increase the cache size
491
                options.cacheLength++;
492
                // add to the cache
493
                add(i, value);
494
            });
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
495
        }
496
497
        // populate any existing data
498
        setTimeout(populate, 25);
499
500
        function flush() {
501
            data = {};
502
            length = 0;
503
        }
504
505
        return {
506
            flush: flush,
507
            add: add,
508
            populate: populate,
509
            load: function (q) {
510
                if (!options.cacheLength || !length)
511
                    return null;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
512
                /*
513
                 * if dealing w/local data and matchContains than we must make sure
514
                 * to loop through all the data collections looking for matches
515
                 */
516
                if (!options.url && options.matchContains) {
517
                    // track all matches
518
                    var csub = [];
519
                    // loop through all the data grids for matches
520
                    for (var k in data) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
521
                        // don't search through the stMatchSets[""] (minChars: 0) cache
522
                        // this prevents duplicates
523
                        if (k.length > 0) {
524
                            var c = data[k];
525
                            $.each(c, function (i, x) {
526
                                // if we've got a match, add it to the array
527
                                if (matchSubset(x.value, q)) {
528
                                    csub.push(x);
529
                                }
530
                            });
531
                        }
532
                    }
533
                    return csub;
534
                } else
535
                // if the exact item exists, use it
536
                if (data[q]) {
537
                    return data[q];
538
                } else if (options.matchSubset) {
539
                    for (var i = q.length - 1; i >= options.minChars; i--) {
540
                        var c = data[q.substr(0, i)];
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable c already seems to be declared on line 524. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
541
                        if (c) {
542
                            var csub = [];
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable csub already seems to be declared on line 518. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
543
                            $.each(c, function (i, x) {
544
                                if (matchSubset(x.value, q)) {
545
                                    csub[csub.length] = x;
0 ignored issues
show
Bug introduced by
The variable csub is changed as part of the for loop for example by [] on line 542. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
546
                                }
547
                            });
548
                            return csub;
549
                        }
550
                    }
551
                }
552
                return null;
553
            }
554
        };
555
    };
556
557
    $.Autocompleter.Select = function (options, input, select, config) {
558
        var CLASSES = {
559
            ACTIVE: "ac_over"
560
        };
561
562
        var listItems,
563
            active = -1,
564
            data,
565
            term = "",
566
            needsInit = true,
567
            element,
568
            list;
569
570
        // Create results
571
        function init() {
572
            if (!needsInit)
573
                return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
574
            element = $("<div/>")
575
                .hide()
576
                .addClass(options.resultsClass)
577
                .css("position", "absolute")
578
                .appendTo(document.body);
579
580
            list = $("<ul/>").appendTo(element).mouseover(function (event) {
581
                if (target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
582
                    active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
583
                    $(target(event)).addClass(CLASSES.ACTIVE);
584
                }
585
            }).click(function (event) {
586
                $(target(event)).addClass(CLASSES.ACTIVE);
587
                select();
588
                // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
589
                input.focus();
590
                return false;
591
            }).mousedown(function () {
592
                config.mouseDownOnSelect = true;
593
            }).mouseup(function () {
594
                config.mouseDownOnSelect = false;
595
            });
596
597
            if (options.width > 0)
598
                element.css("width", options.width);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
599
600
            needsInit = false;
601
        }
602
603
        function target(event) {
604
            var element = event.target;
605
            while (element && element.tagName != "LI")
606
                element = element.parentNode;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
607
            // more fun with IE, sometimes event.target is empty, just ignore it then
608
            if (!element)
609
                return [];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
610
            return element;
611
        }
612
613
        function moveSelect(step) {
614
            listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
615
            movePosition(step);
616
            var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
617
            if (options.scroll) {
618
                var offset = 0;
619
                listItems.slice(0, active).each(function () {
620
                    offset += this.offsetHeight;
621
                });
622
                if ((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
623
                    list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
624
                } else if (offset < list.scrollTop()) {
625
                    list.scrollTop(offset);
626
                }
627
            }
628
        };
629
630
        function movePosition(step) {
631
            active += step;
632
            if (active < 0) {
633
                active = listItems.size() - 1;
634
            } else if (active >= listItems.size()) {
635
                active = 0;
636
            }
637
        }
638
639
        function limitNumberOfItems(available) {
640
            return options.max && options.max < available
641
                ? options.max
642
                : available;
643
        }
644
645
        function fillList() {
646
            list.empty();
647
            var max = limitNumberOfItems(data.length);
648
            for (var i = 0; i < max; i++) {
649
                if (!data[i])
650
                    continue;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
651
                var formatted = options.formatItem(data[i].data, i + 1, max, data[i].value, term);
652
                if (formatted === false)
653
                    continue;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
654
                var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i % 2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
655
                $.data(li, "ac_data", data[i]);
656
            }
657
            listItems = list.find("li");
658
            if (options.selectFirst) {
659
                listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
660
                active = 0;
661
            }
662
            // apply bgiframe if available
663
            if ($.fn.bgiframe)
664
                list.bgiframe();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
665
        }
666
667
        return {
668
            display: function (d, q) {
669
                init();
670
                data = d;
671
                term = q;
672
                fillList();
673
            },
674
            next: function () {
675
                moveSelect(1);
676
            },
677
            prev: function () {
678
                moveSelect(-1);
679
            },
680
            pageUp: function () {
681
                if (active != 0 && active - 8 < 0) {
682
                    moveSelect(-active);
683
                } else {
684
                    moveSelect(-8);
685
                }
686
            },
687
            pageDown: function () {
688
                if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
689
                    moveSelect(listItems.size() - 1 - active);
690
                } else {
691
                    moveSelect(8);
692
                }
693
            },
694
            hide: function () {
695
                element && element.hide();
696
                listItems && listItems.removeClass(CLASSES.ACTIVE);
697
                active = -1;
698
            },
699
            visible: function () {
700
                return element && element.is(":visible");
701
            },
702
            current: function () {
703
                return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
704
            },
705
            show: function () {
706
                var offset = $(input).offset();
707
                element.css({
708
                    width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
709
                    top: offset.top + input.offsetHeight,
710
                    left: offset.left
711
                }).show();
712
                if (options.scroll) {
713
                    list.scrollTop(0);
714
                    list.css({
715
                        maxHeight: options.scrollHeight,
716
                        overflow: 'auto'
717
                    });
718
719
                    if ($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
720
                        var listHeight = 0;
721
                        listItems.each(function () {
722
                            listHeight += this.offsetHeight;
723
                        });
724
                        var scrollbarsVisible = listHeight > options.scrollHeight;
725
                        list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight);
726
                        if (!scrollbarsVisible) {
727
                            // IE doesn't recalculate width when scrollbar disappears
728
                            listItems.width(list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")));
729
                        }
730
                    }
731
732
                }
733
            },
734
            selected: function () {
735
                var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
736
                return selected && selected.length && $.data(selected[0], "ac_data");
737
            },
738
            emptyList: function () {
739
                list && list.empty();
740
            },
741
            unbind: function () {
742
                element && element.remove();
743
            }
744
        };
745
    };
746
747
    $.Autocompleter.Selection = function (field, start, end) {
748
        if (field.createTextRange) {
749
            var selRange = field.createTextRange();
750
            selRange.collapse(true);
751
            selRange.moveStart("character", start);
752
            selRange.moveEnd("character", end);
753
            selRange.select();
754
        } else if (field.setSelectionRange) {
755
            field.setSelectionRange(start, end);
756
        } else {
757
            if (field.selectionStart) {
758
                field.selectionStart = start;
759
                field.selectionEnd = end;
760
            }
761
        }
762
        field.focus();
763
    };
764
765
})(jQuery);
766